﻿using System.Diagnostics;
using System.IO;
using System.Windows;
using K9Nano.Updater.Client.Mvvm;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace K9Nano.Updater.Client.ViewModels;

public class MainWindowViewModel : BindableBase
{
    private string _title;
    private string _currentVersion;
    private AvailableVersion _latestVersion;
    private double _progress;
    private bool _canCancel;
    private bool _canSubmit = true;
    private bool _canShowLog;
    private bool _canClose = true;
    private readonly UpdaterOptions _updaterOptions;
    private readonly IUpdateManager _updateManager;
    private CancellationTokenSource? _cancelCts = null;
    private bool _startApp;
    private bool _success;

    public MainWindowViewModel(IOptions<UpdaterOptions> optionsAccessor, IUpdateManager updateManager)
    {
        _updaterOptions = optionsAccessor.Value;
        _title = _updaterOptions.MainAppName;
        _updateManager = updateManager;
        CurrentVersion = _updaterOptions.Version;

        StartAppTip = $"更新完成后启动 " + _updaterOptions.MainAppName;

        CancelCommand = new RelayCommand(OnCancel);
        CloseCommand = new RelayCommand(OnClose);
        SubmitCommand = new RelayCommand(OnSubmit);
        ShowLogCommand = new RelayCommand(OnShowLog);
    }

    public string Title { get => _title; set => SetProperty(ref _title, value); }

    public string CurrentVersion { get => _currentVersion; set => SetProperty(ref _currentVersion, value); }

    public AvailableVersion LatestVersion { get => _latestVersion; set => SetProperty(ref _latestVersion, value); }

    public double Progress { get => _progress; set => SetProperty(ref _progress, value); }

    public bool CanCancel { get => _canCancel; set => SetProperty(ref _canCancel, value); }

    public bool CanSubmit { get => _canSubmit; set => SetProperty(ref _canSubmit, value); }

    public bool CanClose { get => _canClose; set => SetProperty(ref _canClose, value); }

    public bool CanShowLog { get => _canShowLog; set => SetProperty(ref _canShowLog, value); }

    public bool StartApp { get => _startApp; set => SetProperty(ref _startApp, value); }

    public bool Success { get => _success; set => SetProperty(ref _success, value); }

    public string StartAppTip { get; }

    public Action<LogLevel, string>? ReportLogging { get; set; }

    public RelayCommand CancelCommand { get; }

    public RelayCommand CloseCommand { get; }

    public RelayCommand SubmitCommand { get; }

    public RelayCommand ShowLogCommand { get; }

    private void LogError(string message) => ReportLogging?.Invoke(LogLevel.Error, message);

    private void LogInfo(string message) => ReportLogging?.Invoke(LogLevel.Information, message);

    private void LogWarning(string message) => ReportLogging?.Invoke(LogLevel.Warning, message);

    private void OnCancel()
    {
        _cancelCts?.Cancel();

        CanCancel = false;
        CanSubmit = false;
        CanClose = true;
    }

    private void OnClose()
    {
        if (StartApp)
        {
            try
            {
                Process.Start(_updaterOptions.MainApp);
            }
            catch (Exception ex)
            {
                LogError("启动程序失败，" + ex.Message);
            }
        }

        _cancelCts?.Cancel();
        IocHelper.GetService<MainWindow>().Close();
    }

    private void ReportProgress(double progress)
    {
        Application.Current.Dispatcher.InvokeAsync(() => Progress = progress);
    }

    private async void OnSubmit()
    {
        var appName = _updaterOptions.MainApp.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)
              ? _updaterOptions.MainApp[0..^4]
              : _updaterOptions.MainApp;
        var app = Process.GetProcessesByName(appName).FirstOrDefault();
        if (app != null)
        {
            if (LatestVersion.Force)
            {
                LogWarning($"目标版本要求强制更新，{_updaterOptions.MainAppName}即将退出");
                app.Kill();
            }
            else
            {
                MessageBox.Show(Application.Current.MainWindow,
                    $"{_updaterOptions.MainAppName}({app.Id})正在运行，更新前请先退出",
                    "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        CanShowLog = false;
        if (_cancelCts != null)
        {
            _cancelCts.Cancel();
        }
        _cancelCts = new CancellationTokenSource();
        CanCancel = true;
        CanSubmit = false;
        CanClose = false;

        try
        {
            Success = await _updateManager.TryUpdateAsync(ReportProgress, _cancelCts.Token);           
        }
        catch (Exception ex)
        {
            LogError(ex.Message);
        }
        finally
        {
            CanCancel = false;
            CanSubmit = false;
            CanClose = true;
            CanShowLog = true;

            if (Success)
            {
                LogInfo("更新成功");
            }
            else
            {
                LogError("更新失败");
            }
        }
    }

    private void OnShowLog()
    {
        if (!File.Exists(Constants.LogFile))
        {
            MessageBox.Show("未找到日志文件", "错误", button: MessageBoxButton.OK, icon: MessageBoxImage.Error);
            return;
        }

        try
        {
            Process.Start("NotePad.exe", Constants.LogFile);
        }
        catch (Exception ex)
        {
            MessageBox.Show("无法打开日志文件: " + ex.Message, "错误", button: MessageBoxButton.OK, icon: MessageBoxImage.Error);
        }
    }
}
